#include "sys.h"
void DeForm_GMHeader(G_MACHeader *GMHeader,BUFFER **buf)
{
	uint64 rsv;//it's a reserved bit 
	DeFormat2Val(buf,(uint64 *)&GMHeader->Type,L_GHeader_Type);
	DeFormat2Val(buf,(uint64 *)&GMHeader->ESF,L_GHeader_ESF);
	DeFormat2Val(buf,(uint64 *)&GMHeader->CI,L_GHeader_CI);
	DeFormat2Val(buf,(uint64 *)&GMHeader->EKS,L_GHeader_EKS);
	DeFormat2Val(buf,&rsv,1);
	DeFormat2Val(buf,(uint64 *)&GMHeader->LEN,L_GHeader_LEN);
	DeFormat2Val(buf,(uint64 *)&GMHeader->CID,L_GHeader_CID);
	DeFormat2Val(buf,(uint64 *)&GMHeader->HCS,L_GHeader_HCS);
	PrintMsg("----------","Decode Header","----------");
	PrintMsgVal("GMHeader","Type",GMHeader->Type);
	PrintMsgVal("GMHeader","ESF",GMHeader->ESF);
	PrintMsgVal("GMHeader","CI",GMHeader->CI);
	PrintMsgVal("GMHeader","EKS",GMHeader->EKS);
	PrintMsgVal("GMHeader","LEN",GMHeader->LEN);
	PrintMsgVal("GMHeader","CID",GMHeader->CID);
}	
void DeForm_FSH(Header *H,BUFFER **buf)
{
	uint64 rsv;
	DeFormat2Val(buf,(uint64 *)&H->FSH.Fc,L_FSH_FC);
	if(H->ForARQ==1)
	{
		DeFormat2Val(buf,(uint64 *)&H->FSH.BSN,L_FSH_BSN);
		H->GMHeader.LEN -= 2;
	}
	else
	{
		if(H->ForExt)
		{
			DeFormat2Val(buf,(uint64 *)&H->FSH.FSN,L_FSH_FSN_0);			
			H->GMHeader.LEN -= 2;
		}
		else
		{
			DeFormat2Val(buf,(uint64 *)&H->FSH.FSN,L_FSH_FSN_1 );			
			H->GMHeader.LEN -= 1;
		}
		DeFormat2Val(buf,&rsv,3);
	}
}
void DeForm_PSH(Header *H,BUFFER **buf)
{
	DeFormat2Val(buf,(uint64 *)&H->PSH.Fc,L_PSH_FC );
	if(H->ForARQ==1)
	{
		DeFormat2Val(buf,(uint64 *)&H->PSH.BSN,L_PSH_BSN );
		H->GMHeader.LEN -= 3;
	}
	else
	{
		if(H->ForExt)
		{
			DeFormat2Val(buf,(uint64 *)&H->PSH.FSN,L_PSH_FSN_0 );
			H->GMHeader.LEN -= 3;
		}
		else
		{
			DeFormat2Val(buf,(uint64 *)&H->PSH.FSN,L_PSH_FSN_1 );			
			H->GMHeader.LEN -= 2;
		}
	}
	DeFormat2Val(buf,(uint64 *)&H->PSH.Length,L_PSH_LENGTH);
}
void Decode_Sig1_Proc(BUFFER **buf,BWRList **bwrlist)
{
	uint64  type =0;
	uint64  hcs = 0;
	//	uint64 rsv;//it's a reserved bit 
	DeFormat2Val(buf,&type,3);
	switch(type)
	{
	case 0:
		DeFormat2Val(buf,(uint64 *)&(*bwrlist)->bytes,19);
		DeFormat2Val(buf,(uint64 *)&(*bwrlist)->cid,16);
		DeFormat2Val(buf,&hcs,8);
		(*bwrlist)->BWRtype = INCBWR ;
		AddBWRList(bwrlist);
		break;
	case 1:
		DeFormat2Val(buf,(uint64 *)&(*bwrlist)->bytes,19);
		DeFormat2Val(buf,(uint64 *)&(*bwrlist)->cid,16);
		DeFormat2Val(buf,&hcs,8);
		(*bwrlist)->BWRtype = AGTBWR ;
		AddBWRList(bwrlist);
		break;
	default:
		printf("future work!\n");
		break;
	}

}
void Decode_Sig2_Proc(){}
void DeForm_GMHType(GMHType *type,Header *header)
{
	uint8 tmp = (uint8 )header->GMHeader.Type;
	type->MeshSH  = tmp >>5 &0x1;
	type->ARQFBPd = tmp >>4 &0x1;
	header->ForExt =type->ExtType = tmp >>3 &0x1;
	type->FragSH  = tmp >>2 &0x1;
	type->PackSH  = tmp >>1 &0x1;
	type->FBGMSH  = tmp     &0x1;
}


void Copy_PayLoadTQ(BUFFER **buf,uint32 Fc,MDQ **sduQ,uint32 size)//Copy PayLoad To Queue
{
	uint32 *tmpbuf;
	tmpbuf = (uint32 *)malloc(sizeof(uint8)*size);
	memcpy(tmpbuf,(*buf)->buffer,sizeof(uint8)*size);
	Insert_DataQ_DList(&(*sduQ)->dataQ,tmpbuf,size);
	(*sduQ)->Qlength +=size;
	(*buf)->buffer += size;
	(*sduQ)->dataQ->prev->status=Fc;
}
MDQ * Search_CID(MDQ **headsduQ,uint32 cid)
{
	MDQ *tmpptr = NULL;
	MDQ *sduQ = NULL;
	sduQ = *headsduQ;
	if(sduQ==NULL)
	{
		Append_PDUQ(&sduQ,NULL,0,0,cid);
		*headsduQ = sduQ;
	}
	else
	{
		while(sduQ!=NULL)
		{
			if(sduQ->CID == cid)
				return sduQ;//goto label1;
			else
			{
				tmpptr = sduQ;
				sduQ=sduQ->next;

			}
		}
		Append_PDUQ(&sduQ,NULL,0,0,cid);
		tmpptr->next = sduQ;
	}
	return sduQ;
	//label1:;
}
extern SCID_List *scid;
void Decode_Msg(BUFFER **buf,MsgList **msglist,Header *header)
{
	MMSG *mmsg = NULL;
	uint64 MMType = 0;
	uint8 *cutptr = (*buf)->buffer + header->GMHeader.LEN;

	//SCID_List *scid=NULL;
	mmsg = (MMSG *)malloc(sizeof(MMSG));
	if(Compare_CRC((*buf)->buffer,header->GMHeader.LEN))
	{
		while((*buf)->buffer < cutptr)
		{
			DeFormat2Val(buf,&MMType,8); 
			switch(MMType)
			{		
			case TYPE_UCD:
				DeForm_UCD(buf,&mmsg->ucd);
				break;
			case TYPE_DCD:
				DeForm_DCD(buf,&mmsg->dcd);
				break;
			case TYPE_DLMAP:
				DeForm_DLMAP(buf,&mmsg->dlmap,scid);
				break;
			case TYPE_ULMAP:
				DeForm_ULMAP(buf,&mmsg->ulmap,scid);
				break;
			case TYPE_RNGRSP:
				DeFormRNGRSP(buf,&mmsg->rngrsp);
				break;
			default:
				break;
			}
			*msglist = Append_Msg_List(msglist,(uint16)MMType,(uint16)header->CID,mmsg);
			if((*buf)->bitoffset>0)
			{
				(*buf)->buffer++;
				(*buf)->bitoffset = 0;
			}
		}
		(*buf)->buffer += L_CRC;
	}
	else
	{
		(*buf)->buffer += header->GMHeader.LEN + L_CRC;
	}
}
void DecodeData(BUFFER **buf,Header *header,MDQ **headsduQ)
{
	MDQ *sduQ = NULL;
	GMHType type;
	sduQ = Search_CID(headsduQ,header->GMHeader.CID);
	//--- Compare  CRC ---//
	if(Compare_CRC((*buf)->buffer,header->GMHeader.LEN))
	{
		DeForm_GMHType(&type,header);
		//Porcess Mesh Subheader 
		//Process Grant Management SubHeader
		//Process Fragment  SubHeader
		if(type.FragSH==1)
			DeForm_FSH(header,buf);
		//Process Fast FeedBack SubHeader 
		//Packing SubHeader
		if(type.PackSH==1)//DePacking Process
		{
			do{
				DeForm_PSH(header,buf);
				Copy_PayLoadTQ(buf,header->PSH.Fc,&sduQ,header->PSH.Length);
				header->GMHeader.LEN -= header->PSH.Length;
			}while(header->GMHeader.LEN > 0);
		}
		else//DeFragment Process
			Copy_PayLoadTQ(buf,header->FSH.Fc,&sduQ,header->GMHeader.LEN);
		// --- added CRC byte and shift position --- //
		(*buf)->buffer += L_CRC;
	}
	else
	{
		(*buf)->buffer += header->GMHeader.LEN + L_CRC;
	}
}
void Decode_GMH_Proc(BUFFER ** buf ,Header *header,MDQ **headsduQ,MsgList **msglist)	
{


	GMHType type;
	uint32 usr = 0;
	uint32 cidtype=0;

	Init_GMHType(&type);
	DeForm_GMHeader(&header->GMHeader,buf);
	header->GMHeader.LEN -= (L_MACHEADER+L_CRC);
	//--- need to search the right CID and pass it to Copy_PayloadTQ ---//
	SrhCMT(&tableCMT,header->GMHeader.CID,&usr,&cidtype);
	if( cidtype == BASIC_CID || cidtype == PRIMARY_CID || cidtype == BROADCAST_CID )
	{
		PrintMsg("----------","Decode Msg","----------");
		Decode_Msg(buf,msglist,header);
	}
	else if( cidtype == TRANSPORT_UGS_CID || cidtype == TRANSPORT_RTPS_CID || cidtype == TRANSPORT_NRTPS_CID || cidtype == TRANSPORT_BS_CID )
	{
		PrintMsg("----------","Decode Data","----------");
		DecodeData(buf,header,headsduQ);
	}
	else if(cidtype==PADDING_CID)
	{
	}
}
void Decode_PDU(BUFFER **buf,MDQ **sduQ,MsgList **msglist,BWRList **bwrlist)
{
	Header header;
	uint32 HC=0;
	Init_Header(&header);

	DeFormat2Val(buf,(uint64 *)&header.GMHeader.HT,L_GHeader_HT);
	DeFormat2Val(buf,(uint64 *)&header.GMHeader.EC,L_GHeader_EC);
	HC = (header.GMHeader.HT<<1) + header.GMHeader.EC;

	switch(HC)
	{
	case 0x0:Decode_GMH_Proc(buf,&header,sduQ,msglist);//DeForm_GMHeader(header.GMHeader,buf);
		break;
	case 0x1:
		break;
	case 0x2:Decode_Sig1_Proc(buf,bwrlist);//DeForm_SigHeader1();
		break;
	case 0x3:Decode_Sig2_Proc();//DeForm_SigHeader2();
		break;
	default :
		break;
	}
}
void Reassmble(MDQ **sduQ_RX)
{
	uint32 Qlength=0;
	uint8 *SDU = NULL;
	MDQ  *tmpptr = NULL;
	uint8 *SDUhead = NULL;
	uint32 sdulength = 0;
	sdulength = Qlength = Acc_PQLength(*sduQ_RX);
	SDUhead = malloc(sizeof(uint8)*Qlength);
	SDU = SDUhead;
	while(Qlength>0)
	{
		memcpy(SDU,(*sduQ_RX)->dataQ->ptr,(*sduQ_RX)->dataQ->length);
		Qlength -= (*sduQ_RX)->dataQ->length;
		//update the sdu info
		SDU += (*sduQ_RX)->dataQ->length;
		//update sduQ_RX info
		(*sduQ_RX)->Qlength -= (*sduQ_RX)->dataQ->length;
		(*sduQ_RX)->dataQ = (*sduQ_RX)->dataQ->next;
		Delete_DataQ_DList((*sduQ_RX)->dataQ->prev);
		//update the MDQ info
		if((*sduQ_RX)->Qlength==0)
		{
			tmpptr =(*sduQ_RX);
			(*sduQ_RX)=(*sduQ_RX)->next;
			free(tmpptr);
		}
	}
	fwrite(SDUhead,sizeof(char),sdulength,OutFileUsr1);
	free(SDUhead);
}



void DeformatBroadcastBurst(SDQ *broadcastburst , MsgList **msglist)
{
	BUFFER *buf=NULL;
	uint8 *total=0;
	MMSG *mmsg=NULL;
	MDQ  *sduQ_RX=NULL;
	BWRList **bwrlist=NULL;
	int i =0;

	buf = (BUFFER *)malloc(sizeof(BUFFER));
	buf->base = NULL;
	buf->buffer = (uint8 *)broadcastburst->ptr ;
	buf->bitoffset = 0;
	total = broadcastburst->length + buf->buffer;
	PrintMsg("DeformatBroBurst","<< Start  >>","---------->");
	//First to Decode FCH
	for(i=0;i<4;i++)
	{
		mmsg = (MMSG *)malloc(sizeof(MMSG));
		DeForm_FCH(&buf,&mmsg->fch);
		*msglist = Append_Msg_List(msglist,TYPE_FCH,0xFFFF,mmsg);
	}

	//Second to Decode DLMAP
	mmsg = (MMSG *)malloc(sizeof(MMSG));
	DeForm_DLMAP(&buf,&mmsg->dlmap,scid);
	*msglist = Append_Msg_List(msglist,TYPE_DLMAP,0xFFFF,mmsg);
	//check the padding nibble in the DLMAP if there is nibble ,buffer must be shift to fit the correct position!
	if(buf->bitoffset>0)
	{
		buf->buffer++;
		buf->bitoffset = 0;
	}


	//Then Decode ULMAP and DCD UCD or Broadcast Msg	
	while(total>buf->buffer)
	{
		Decode_PDU(&buf,&sduQ_RX,msglist,bwrlist);
		//Decode_Msg(&buf,msglist,0xFFFF);
	}
	PrintMsg("DeformatBroBurst","<< Finsih >>","---------->");
}

void DeformatUsrBurst(SDQ *usrburst,MsgList **msglist,BWRList **bwrlist)
{

	MDQ  *sduQ_RX=NULL;
	BUFFER *buf=NULL;
	uint8 *total=0;
	if(usrburst != NULL)
	{
		PrintMsg("DeformatUsrBurst","<< Start  >>","---------->");
		buf = (BUFFER *)malloc(sizeof(BUFFER));
		buf->base = NULL;
		buf->buffer = (uint8 *)usrburst->ptr ;
		buf->bitoffset = 0;
		total = usrburst->length + buf->buffer;
		while(total>buf->buffer)
		{
			Decode_PDU(&buf,&sduQ_RX,msglist,bwrlist);
		}
		Reassmble(&sduQ_RX);
		PrintMsg("DeformatUsrBurst","<< Finish >>","<----------");
	}
}
